package com.frontop.terminal.vlcjplayer;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.frontop.terminal.constant.CommonNumBerCodConst;
import com.frontop.terminal.constant.PlayStatusConst;
import com.frontop.terminal.entity.TerminalConfig;
import com.frontop.terminal.util.FileUtils;
import com.frontop.terminal.util.ReadDataUtil;
import com.frontop.terminal.util.TerminalApplictionContextUtil;
import com.frontop.terminal.vlcjplayer.event.RendererAddedEvent;
import com.frontop.terminal.vlcjplayer.event.RendererDeletedEvent;
import com.frontop.terminal.vlcjplayer.event.ShutdownEvent;
import com.frontop.terminal.vlcjplayer.view.main.MainFrame;
import com.sun.jna.NativeLibrary;
import uk.co.caprica.nativestreams.NativeStreams;
import uk.co.caprica.vlcj.binding.RuntimeUtil;
import uk.co.caprica.vlcj.player.base.MarqueePosition;
import uk.co.caprica.vlcj.player.component.CallbackMediaPlayerComponent;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.renderer.RendererDiscoverer;
import uk.co.caprica.vlcj.player.renderer.RendererDiscovererDescription;
import uk.co.caprica.vlcj.player.renderer.RendererDiscovererEventListener;
import uk.co.caprica.vlcj.player.renderer.RendererItem;
import uk.co.caprica.vlcj.support.Info;

import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.frontop.terminal.vlcjplayer.Application.application;

/**
 * Application entry-point.
 *
 * @author Guodong
 */
public class VlcjPlayer implements RendererDiscovererEventListener {

    private static final NativeStreams NATIVE_STREAMS;
    private static final List<RendererDiscoverer> RENDERER_DISCOVERERS = new ArrayList<>();
    private static JFrame mainFrame;

    static {
        NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "/lib");
    }

    // Redirect the native output streams to files, useful since VLC can generate a lot of noisy native logs we don't care about
    // (on the other hand, if we don't look at the logs we might won't see errors)
    static {
//        if (RuntimeUtil.isNix()) {
//            nativeStreams = new NativeStreams("stdout.log", "stderr.log");
//        }
//        else {99
        NATIVE_STREAMS = null;
//        }
    }

//    private final NativeLog nativeLog;

    public VlcjPlayer() {
        EmbeddedMediaPlayerComponent mediaPlayerComponent = application().mediaPlayerComponent();
        CallbackMediaPlayerComponent callbackMediaPlayerComponent = application().callbackMediaPlayerComponent();

        prepareDiscoverers();

        mainFrame = new MainFrame();

        TerminalConfig terminalConfig = ReadDataUtil.getTerminalConfig();
        if (Objects.nonNull(terminalConfig)) {
            //播放器工具栏不隐藏就显示,否则什么都不做
            if (terminalConfig.isPlayerToolbarHide()) {
                //窗口无装饰模式
                mainFrame.setUndecorated(true);
            }
        }

        mainFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                // Stop audio as soon as possible
//                application().mediaPlayer().controls().stop();
//
//                // Avoid the visible delay disposing everything
//                System.out.println("关闭播放器");
//                mainFrame.setVisible(false);
//
//                for (RendererDiscoverer discoverer : RENDERER_DISCOVERERS) {
//                    discoverer.stop();
//                }
//
//                mediaPlayerComponent.release();
//                callbackMediaPlayerComponent.release();
//
//                if (NATIVE_STREAMS != null) {
//                    NATIVE_STREAMS.release();
//                }
//
//                application().post(ShutdownEvent.INSTANCE);
            }

            @Override
            public void windowClosed(WindowEvent e) {
            }
        });
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        application().mediaPlayerComponent().mediaPlayer().fullScreen().strategy(new VlcjPlayerFullScreenStrategy(mainFrame));
        application().callbackMediaPlayerComponent().mediaPlayer().fullScreen().strategy(new VlcjPlayerFullScreenStrategy(mainFrame));

//        nativeLog = mediaPlayerComponent.mediaPlayerFactory().application().newLog();

//        JFrame messagesFrame = new NativeLogFrame(nativeLog);
//        JFrame effectsFrame = new EffectsFrame();
//        JFrame debugFrame = new DebugFrame();
    }

    public static void main(String[] args) throws InterruptedException {
        Info info = Info.getInstance();

        System.out.printf("vlcj             : %s%n", info.vlcjVersion() != null ? info.vlcjVersion() : "<version not available>");
        System.out.printf("os               : %s%n", val(info.os()));
        System.out.printf("java             : %s%n", val(info.javaVersion()));
        System.out.printf("java.home        : %s%n", val(info.javaHome()));
        System.out.printf("jna.library.path : %s%n", val(info.jnaLibraryPath()));
        System.out.printf("java.library.path: %s%n", val(info.javaLibraryPath()));
        System.out.printf("PATH             : %s%n", val(info.path()));
        System.out.printf("VLC_PLUGIN_PATH  : %s%n", val(info.pluginPath()));

        if (RuntimeUtil.isNix()) {
            System.out.printf("LD_LIBRARY_PATH  : %s%n", val(info.ldLibraryPath()));
        } else if (RuntimeUtil.isMac()) {
            System.out.printf("DYLD_LIBRARY_PATH          : %s%n", val(info.dyldLibraryPath()));
            System.out.printf("DYLD_FALLBACK_LIBRARY_PATH : %s%n", val(info.dyldFallbackLibraryPath()));
        }

        setLookAndFeel();

        VlcjPlayer app = new VlcjPlayer();
        app.start();

    }

    private static String val(String val) {
        return val != null ? val : "<not set>";
    }

    public static void setLookAndFeel() {
        String lookAndFeelClassName;
        if (RuntimeUtil.isNix()) {
            lookAndFeelClassName = "javax.swing.plaf.nimbus.NimbusLookAndFeel";
        } else {
            lookAndFeelClassName = UIManager.getSystemLookAndFeelClassName();
        }
        try {
            UIManager.setLookAndFeel(lookAndFeelClassName);
        } catch (Exception e) {
            // Silently fail, it doesn't matter
        }
    }

    public static void play(String resourcePath) {
        if (!StrUtil.isEmpty(resourcePath)) {
            application().addRecentMedia(resourcePath);
            application().mediaPlayer().media().play(resourcePath);

            //记录当前切换到了播放器
            TerminalApplictionContextUtil.CURRENT_FOCUS_TASK = CommonNumBerCodConst.ON;

            Integer repeatStatus = Objects.requireNonNull(ReadDataUtil.getTerminalConfig()).getPlayMode();
            boolean resourceType = FileUtils.isImg(FileUtil.getSuffix(resourcePath));
            //如果是图片 && 当前是单个循环那就暂停
            if (repeatStatus.equals(PlayStatusConst.PLAYP_PATTERN_ON) && resourceType) {
                ThreadUtil.sleep(600);
                VlcjPlayer.pause();
                System.out.println("当前播放是图片类型，自动暂停");
            }
        } else {
            System.out.println("播放资源时资源路径为空");
            TerminalApplictionContextUtil.CURRENT_FOCUS_TASK = CommonNumBerCodConst.ZERO;
        }
    }

    public static void pause() {
        application().mediaPlayer().controls().pause();
    }

    @SuppressWarnings("unused")
    public static void insertMarquee() {
        application().mediaPlayer().marquee().setText("程序试用期结束,请购买正版!\r\nThe trial period of the program is over, please purchase the genuine copy！");
        application().mediaPlayer().marquee().enable(true);
        application().mediaPlayer().marquee().setOpacity(127);
        application().mediaPlayer().marquee().setPosition(MarqueePosition.CENTRE);
    }

    public static void vlcPlayerVisible(boolean b) {
        if (null != mainFrame) {
            mainFrame.setVisible(b);
            //隐藏的同时停止视频
            if (!b) {
                application().mediaPlayer().controls().stop();
            }
        }
    }

    public static void vlcPlayerFullScreen(boolean b) {
        application().mediaPlayer().fullScreen().set(b);
    }

    public static void exit() {
        // Stop audio as soon as possible
        application().mediaPlayer().controls().stop();

        // Avoid the visible delay disposing everything
        System.out.println("关闭播放器");
        mainFrame.setVisible(false);

        for (RendererDiscoverer discoverer : RENDERER_DISCOVERERS) {
            discoverer.stop();
        }

        application().callbackMediaPlayerComponent().release();
        application().mediaPlayerComponent().release();

        if (NATIVE_STREAMS != null) {
            NATIVE_STREAMS.release();
        }

        application().post(ShutdownEvent.INSTANCE);
    }

    /**
     * 设置播放器窗口大小与位置
     */
    private void setPlayerSizeAndLocal() {
        TerminalConfig terminalConfig = ReadDataUtil.getTerminalConfig();
        String str = "-";

        if (Objects.nonNull(terminalConfig)) {
            //判断播放已取消全屏
            if (!terminalConfig.isPlayerFullScreen()) {
                //取消全屏的话播放器窗口按指定大小显示
                String playerSize = terminalConfig.getPlayerSize();
                if (null != playerSize && !"".equals(playerSize) && playerSize.contains(str)) {
                    //截取宽度和高度
                    String[] windthOrHieght = playerSize.split(str);
                    if (windthOrHieght.length == CommonNumBerCodConst.TWO) {
                        //设置窗口大小
                        System.out.println("播放器窗口宽高:" + windthOrHieght[0] + str + windthOrHieght[1]);
                        mainFrame.setSize(Integer.parseInt(windthOrHieght[0]), Integer.parseInt(windthOrHieght[1]));
                    }
                }

                //获取窗口位置
                String playerLocation = terminalConfig.getPlayerLocation();
                if (null != playerLocation && !"".equals(playerLocation) && playerLocation.contains(str)) {
                    //截取宽度和高度
                    String[] xRoY = playerLocation.split(str);
                    if (xRoY.length == CommonNumBerCodConst.TWO) {
                        //设置窗口大小
                        System.out.println("播放器窗口位置:" + xRoY[0] + str + xRoY[1]);
                        mainFrame.setLocation(Integer.parseInt(xRoY[0]), Integer.parseInt(xRoY[1]));
                    }
                }
            }
        }
    }

    public void start() {
        //最顶层显示播放器
        mainFrame.setAlwaysOnTop(true);

        //设置播放器窗口大小与位置
        setPlayerSizeAndLocal();

        for (RendererDiscoverer discoverer : RENDERER_DISCOVERERS) {
            discoverer.start();
        }
    }

    @Override
    public void rendererDiscovererItemAdded(RendererDiscoverer rendererDiscoverer, RendererItem itemAdded) {
        application().post(new RendererAddedEvent(itemAdded));
    }

    @Override
    public void rendererDiscovererItemDeleted(RendererDiscoverer rendererDiscoverer, RendererItem itemDeleted) {
        application().post(new RendererDeletedEvent(itemDeleted));
    }

    private void prepareDiscoverers() {
        EmbeddedMediaPlayerComponent mediaPlayerComponent = application().mediaPlayerComponent();
        for (RendererDiscovererDescription descriptions : mediaPlayerComponent.mediaPlayerFactory().renderers().discoverers()) {
            RendererDiscoverer discoverer = mediaPlayerComponent.mediaPlayerFactory().renderers().discoverer(descriptions.name());
            discoverer.events().addRendererDiscovererEventListener(this);
            RENDERER_DISCOVERERS.add(discoverer);
        }
    }
}
